# Chrome 桥接模式（Bridge Mode）

import { PackageManagerTabs } from '@theme';

使用 Midscene 的 Chrome 插件桥接模式（Bridge Mode），你可以用本地脚本控制桌面版本的 Chrome。你的脚本可以连接到新标签页或当前已激活的标签页。

使用桌面版本的 Chrome 可以让你复用已有的 cookie、插件、页面状态等。你可以使用自动化脚本与操作者互动，来完成你的任务。

![bridge mode](/midscene-bridge-mode.png)

:::info Demo Project
查看桥接模式（Bridge Mode）的样例项目：: [https://github.com/web-infra-dev/midscene-example/blob/main/bridge-mode-demo](https://github.com/web-infra-dev/midscene-example/blob/main/bridge-mode-demo)
:::

## 准备工作

1. 配置 OpenAI API Key，或 [自定义模型和服务商](./model-provider)

```bash
# 更新为你自己的 Key
export OPENAI_API_KEY="sk-abcdefghijklmnopqrstuvwxyz"
```

2. 在 Chrome 应用商店安装 [Midscene 浏览器插件](https://chromewebstore.google.com/detail/midscene/gbldofcpkknbggpkmbdaefngejllnief)

## 第一步：安装依赖

<PackageManagerTabs command="install @midscene/web tsx --save-dev" />

## 第二步：编写脚本

编写并保存以下代码为 `./demo-new-tab.ts`。

```typescript
import { AgentOverChromeBridge } from "@midscene/web/bridge-mode";

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
Promise.resolve(
  (async () => {
    const agent = new AgentOverChromeBridge();

    // 这个方法将连接到你的桌面 Chrome 的新标签页
    // 记得启动你的 Chrome 插件，并点击 'allow connection' 按钮。否则你会得到一个 timeout 错误
    await agent.connectNewTabWithUrl("https://www.bing.com");

    // 这些方法与普通 Midscene agent 相同
    await agent.ai('type "AI 101" and hit Enter');
    await sleep(3000);

    await agent.aiAssert("there are some search results");
    await agent.destroy();
  })()
);
```

## 第三步：启动 Chrome 插件

启动你的桌面 Chrome 和 Midscene 插件，并切换到 'Bridge Mode' 标签页。点击 "Allow connection"。

<p align="center">
  <img src="/bridge_in_extension.png" alt="bridge in extension" width="400"/>
</p>

## 第四步：运行脚本

运行你的脚本

```bash
tsx demo-new-tab.ts
```

执行脚本后，你应该看到 Chrome 插件的状态展示切换为 'connected'，并且新标签页已打开。现在这个标签页由你的脚本控制。

:::info
执行脚本和点击插件中的 'Allow connection' 按钮没有顺序要求。
:::

## 构造器

```typescript
import { AgentOverChromeBridge } from "@midscene/web/bridge-mode";

const agent = new AgentOverChromeBridge();
```

除了 [普通 Agent 构造器](./api.mdx) 的参数，`AgentOverChromeBridge` 还接受以下参数：

* `closeNewTabsAfterDisconnect?: boolean`: 如果为 true，当桥接断开时，所有新创建的标签页都将被自动关闭。默认值为 false。

## 方法

除了 [普通的 Agent 接口](./api.mdx)，`AgentOverChromeBridge` 还提供了一些额外的接口来控制桌面 Chrome。

:::info
你应该在执行其他操作前，先调用 `connectCurrentTab` 或 `connectNewTabWithUrl`。

每个 agent 实例只能连接到一个标签页实例，并且一旦被销毁就无法重新连接，需要重新创建 agent 实例。
:::

### `connectCurrentTab()`

连接到当前已激活的标签页。

* 类型

```typescript
function connectCurrentTab(options?: { 
  forceSameTabNavigation?: boolean 
}): Promise<void>;
```

* 参数：
  * `options?: object` - 可选配置对象
    * `forceSameTabNavigation?: boolean` - 如果为 true（默认值），限制页面打开新的标签页，让新的页面始终在旧的标签页中打开避免人为切换标签页导致 AI 操作失败，正常情况下都不需要更改此配置

* 返回值：
  * 返回一个 Promise。连接成功时解析为 void；若连接失败则抛出错误

* 示例：

```typescript
try {
  await agent.connectCurrentTab();
  console.log('成功连接到当前标签页');
} catch (err) {
  console.error('连接失败:', err.message);
}
```

### `connectNewTabWithUrl()`

创建一个新标签页，并立即连接到它。

* 类型

```typescript
function connectNewTabWithUrl(
  url: string,
  options?: { 
    forceSameTabNavigation?: boolean 
  }
): Promise<void>;
```

* 参数：
  * `url: string` - 新标签页要打开的 URL
  * `options?: object` - 可选配置对象（参数同 connectCurrentTab）

* 返回值：
  * 返回一个 Promise。连接成功时解析为 void；若连接失败则抛出错误

* 示例：

```typescript
// 打开 Bing 并等待连接
await agent.connectNewTabWithUrl(
  "https://www.bing.com",
  { forceSameTabNavigation: false }
);
```

### `destroy()`

销毁连接并释放资源。

* 类型

```typescript
function destroy(closeNewTabsAfterDisconnect?: boolean): Promise<void>;
```

* 参数：
  * `closeNewTabsAfterDisconnect?: boolean` - 如果为 true，当桥接断开时，所有新创建的标签页都将被自动关闭。默认值为 false。这个参数将覆盖构造器中的 `closeNewTabsAfterDisconnect` 参数。

* 返回值：
  * 返回一个 Promise，销毁完成后解析为 void

* 示例：

```typescript
// 完成操作后销毁连接
await agent.ai('执行最终操作...');
await agent.destroy();
```

### 更多接口

Agent 中的常用接口（如 `aiAction`，`aiQuery` 等）请阅读 [API 参考](./api.mdx)。

## 在 YAML 自动化脚本中使用桥接模式

[Yaml 格式的自动化脚本](./automate-with-scripts-in-yaml) 是 Midscene 提供给开发者的一种编写自动化脚本的方式。通过使用 yaml 格式，脚本会变得易于阅读和编写。

在 Yaml 脚本中使用桥接模式时，需要配置 `target` 中的 `bridgeMode` 属性。如果想要使用当前标签页，设置为 `currentTab`，否则设置为 `newTabWithUrl`。

例如，以下脚本将会通过 Chrome 插件的桥接模式打开一个新的标签页：

```diff
target:
  url: https://www.bing.com
+ bridgeMode: newTabWithUrl
tasks:
```

运行脚本：

```bash
midscene ./bing.yaml
```

在运行脚本后，记得要启动 Chrome 插件，并点击 'Allow connection' 按钮。

### 不支持的选项

在桥接模式下，以下选项将不会生效（它们将遵循桌面浏览器的设置）：
- userAgent
- viewportWidth
- viewportHeight
- viewportScale
- waitForNetworkIdle
- cookie


## FAQ

* 我应该在哪里配置 `OPENAI_API_KEY`，在浏览器里还是命令行里？

当你使用桥接模式时，你应该在命令行里配置 `OPENAI_API_KEY`。
